package org.ims.inv.web.action.project;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.ims.inv.model.flow.ModelFlowDef;
import org.ims.inv.model.flow.ModelFlowTemplate;
import org.ims.inv.model.flow.material.ModelFlowMaterial;
import org.ims.inv.model.project.ModelProject;
import org.ims.inv.model.project.ModelProjectMaterial;
import org.ims.inv.model.project.ModelProjectProcess;
import org.ims.inv.model.system.ModelAppDictionary;
import org.ims.inv.service.project.ServiceProject;
import org.ims.inv.web.util.ContextUtil;
import org.springframework.beans.BeanUtils;

import cn.trymore.core.exception.ServiceException;
import cn.trymore.core.log.LogAnnotation;
import cn.trymore.core.util.UtilCollection;
import cn.trymore.core.util.UtilDate;
import cn.trymore.core.util.UtilString;

/**
 * Action: 项目登记
 * 
 * @author Jeccy.Zhao
 *
 */
public class ProjectCheckInAction
extends ProjectBaseAction
{
	/**
	 * The LOGGER
	 */
	private static final Logger LOGGER = Logger.getLogger(ProjectCheckInAction.class);
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 项目登记页面
	 */
	public ActionForward pageProjectCheckIn (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			// 项目表单
			request.setAttribute("dictInds", this.getDictionariesByType("DICT_PRO_INDUSTRY"));
			request.setAttribute("dictPtns", this.getDictionariesByType("DICT_PRO_PARTNER"));
			request.setAttribute("recordTime", new Date());
			request.setAttribute("recommendTime", new Date());
			request.setAttribute("users", this.serviceAppUser.getAllUsers());
			request.setAttribute("recordUser", ContextUtil.getCurrentUser());
			
			this.outWriteAllParameters(request);
			
			return mapping.findForward("page.project.checkin.index");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 加载项目登记表单页面
	 */
	public ActionForward actionLoadProjectTab (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			String tab = request.getParameter("tab");
			
			if (UtilString.isNotEmpty(tab))
			{
				if (TAB_FORM.equalsIgnoreCase(tab))
				{
					// 项目表单
				}
				else if (TAB_MATERIAL.equalsIgnoreCase(tab))
				{
					// 材料区
					request.setAttribute("materials", this.loadRootFlowMaterial(null));
				}
				
				return mapping.findForward("base.project.data." + tab);		
			}
			
			return ajaxPrint(response, getErrorCallback("未支持的Tab加载页面: " + tab));
		}
		catch (ServiceException e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 加载项目登记材料页面
	 */
	public ActionForward actionLoadProjectMaterialTab (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		return mapping.findForward("page.project.tab.material");
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 生成项目编号
	 */
	public ActionForward actionGenerateProjectNo (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			String typeId = request.getParameter("typeId");
			String cTime  = request.getParameter("projectCreationTime");
			
			if (UtilString.isNotEmpty(typeId, cTime))
			{
				ModelAppDictionary type = this.serviceAppDictionary.get(typeId);
				if (type != null)
				{
					ModelProject entity = new ModelProject();
					entity.setProjectType(type);
					entity.setProjectCreationTime(UtilDate.toDate(cTime));
					
					String projectNo = this.generateProjectNo(entity);
					return ajaxPrint(response, "{'statusCode': 200, 'projectNo' : '" + projectNo + "'}");
				}
				else
				{
					return ajaxPrint(response, "{'statusCode': 500, 'error' : '项目行业类别不存在'}");
				}
			}
			else
			{
				return ajaxPrint(response, "{'statusCode': 500, 'error' : '项目行业类别ID不合法或者项目登记时间为空'}");
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 唯一性检测项目编号
	 */
	public ActionForward actionUniqueCheckProjectNo (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		String projectNo = request.getParameter("projectNo");
		String formProjectNo = request.getParameter("formProjectNo");
		
		if (UtilString.isNotEmpty(projectNo))
		{
			try
			{
				if ((UtilString.isNotEmpty(formProjectNo) && formProjectNo.equalsIgnoreCase(projectNo)) || 
						!this.isProjectNoExisted(projectNo))
				{
					return ajaxPrint(response, AJAX_RESPONSE_TRUE);
				}
			} 
			catch (Exception e)
			{
				LOGGER.error("Exception raised when checking dict data", e);
			}
		}
		
		return ajaxPrint(response, AJAX_RESPONSE_FALSE);
	}
	
	
	/**
	 * 判断项目编号是否存在.
	 * 
	 * @param projectNo
	 * @return
	 * @throws Exception
	 */
	private boolean isProjectNoExisted (String projectNo) throws Exception
	{
		ModelProject entity = new ModelProject();
		entity.setProjectNo(projectNo);
		
		if (UtilCollection.isNotEmpty(this.serviceProject.getByCriterion(entity)))
		{
			return true;
		}
		
		return false;
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 保存项目登记信息
	 */
	@LogAnnotation(description="项目信息登记或更新: `${projectName}`",type="项目登记")
	public ActionForward actionSaveProject (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			ModelProject formEntity = (ModelProject)form;
			ModelProject entity = formEntity;
			
			String reject = request.getParameter("decision");
			boolean isActionEdit = this.isObjectIdValid(formEntity.getId());
			
			if (!isActionEdit)
			{
				// 处理项目表单
				handleProjectFormInput(entity, request);
				
				// 项目编号检测
				if (UtilString.isNotEmpty(entity.getProjectNo()) && 
						this.isProjectNoExisted(entity.getProjectNo()))
				{
					return ajaxPrint(response, 
							getErrorCallback("该项目编号已存在:" + entity.getProjectNo()));
				}
				
				// 设置状态为审批中
				entity.setProjectStatus(ModelProject.EProjectStatus.APPROVING.getValue());
				
				// 第一次生成项目材料
				this.generateProjectMaterials(entity);
				
				// 第一次生成审批流程
				this.generateProjectWorkFlow(entity);
				
				// 设置项目进展 - '项目分配'
				entity.setCurrentProcess(null);
				
				// 设置项目提交时间
				entity.setProjectPostTime(new Date());
			}
			else
			{
				entity = this.serviceProject.get(formEntity.getId());
				if (entity != null)
				{
					BeanUtils.copyProperties(formEntity, entity, new String[] {
							"materials", "processForms", "processEvents", "projectStatus", 
							"currentProcess", "projectPostTime", "currentProcess", "projectNo",
							"projectType", "projectRecorder", "archived"});
					
					if (UtilString.isNotEmpty(reject))
					{
						// 否决项目
						entity.setCurrentProcess(null);
						entity.setArchived(ModelProject.EProjectArchived.ARCHIEVED.getValue());
						entity.setProjectStatus(ModelProject.EProjectStatus.SUSPENDED.getValue());
					}
					else
					{
						if (!"realoc".equals(request.getParameter("optype")))
						{
							if (!"edit".equals(request.getParameter("op")))
							{
								// 设置状态为"待提交材料阶段"
								entity.setProjectStatus(ModelProject.EProjectStatus.TOPOST.getValue());
								
								// 设置项目进展
								entity.setCurrentProcess(entity.getProcessByOffset(1));
							}
						}
						else
						{
							// 项目重新分配
						}
					}
					
					// 处理项目表单
					handleProjectFormInput(entity, request);
				}
				else
				{
					return ajaxPrint(response, getErrorCallback("数据实体不存在!"));
				}
			}
			
			// 系统会默认将项目登记人设置成项目经理, 直到项目部长进行项目分配操作后生效..
			if (entity.getProjectManager() == null)
			{
				entity.setProjectManager(entity.getProjectRecorder());
			}
			
			// 保存
			this.serviceProject.save(entity);
			
			// 记录操作事件
			if (!isActionEdit)
			{	
				this.serviceProjectEvent.traceEvent(entity, EVENT_INIT, null, "项目创建");
				
				// 服务器推送至客户端.
				this.getMessagePush().pushMessage(
					this.getAllUserIds(),
					scriptMessageNotify, 
					"menu_item_project_assign",
					1
				);
				
				// 服务器推送至客户端.
				this.getMessagePush().pushMessage(
					entity.getProjectRelevantPersonIds(),
					scriptMessageNotify, 
					"menu_item_project_track",
					1
				);
				
			}
			else
			{
				String op = request.getParameter("op");
				if (UtilString.isNotEmpty(op))
				{
					if ("allocate".equals(op))
					{
						if (!"realoc".equals(request.getParameter("optype")))
						{
							if (UtilString.isNotEmpty(reject))
							{
								// 项目否决
								this.serviceProjectEvent.traceEvent(entity, EVENT_INIT, null, "项目否决");
							}
							else
							{
								// 项目分配
								this.serviceProjectEvent.traceEvent(entity, EVENT_INIT, null, "项目分配");
							}
							
							// 服务器推送至客户端.
							this.getMessagePush().pushMessage(
								this.getAllUserIds(),
								scriptMessageNotify, 
								"menu_item_project_assign",
								-1
							);
						}
						else
						{
							// 重新分配
							this.serviceProjectEvent.traceEvent(entity, EVENT_OTHER, null, "项目重新分配");
						}
					}
				}
			}
			
			if (!isActionEdit)
			{
				return ajaxPrint(response, 
						getSuccessCallback("数据保存成功.", CALLBACK_TYPE_CLOSE, CURRENT_NAVTABID, null, entity.getId(), false));
			}
			else
			{
				return ajaxPrint(response, 
						getSuccessCallback("数据保存成功.", CALLBACK_TYPE_CLOSE, CURRENT_NAVTABID, null, false));
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when saving flow definition data", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * 处理项目表单
	 * 
	 * @param request
	 */
	private void handleProjectFormInput (ModelProject entity, 
			HttpServletRequest request) throws ServiceException
	{
		// 项目行业
		String projTypeId = request.getParameter("projectTypeId");
		if (this.isObjectIdValid(projTypeId))
		{
			entity.setProjectType(this.serviceAppDictionary.get(projTypeId));
		}
		
		// 项目推荐人
		String projReferralId = request.getParameter("projectReferralId");
		if (this.isObjectIdValid(projReferralId))
		{
			entity.setProjectReferral(this.serviceAppUser.get(projReferralId));
		}
		else
		{
			// 其他人
			entity.setProjectReferral(null);
			
			if (UtilString.isNotEmpty(
					request.getParameter("projectReferralName")))
			{
				entity.setProjectReferralName(request.getParameter("projectReferralName"));
			}
			else
			{
				entity.setProjectReferralName(null);
			}
		}
		
		// 项目经理
		String projManagerId = request.getParameter("manager.id");
		if (this.isObjectIdValid(projManagerId))
		{
			entity.setProjectManager(this.serviceAppUser.get(projManagerId));
		}
		
		// 项目合作方类型
		String projPaternerId = request.getParameter("projectPartnerId");
		if (this.isObjectIdValid(projPaternerId))
		{
			entity.setProjectPartnerType(this.serviceAppDictionary.get(projPaternerId));
		}
		
		// 项目登记人
		String projRecorderId = request.getParameter("recorder.id");
		if (this.isObjectIdValid(projRecorderId))
		{
			entity.setProjectRecorder(this.serviceAppUser.get(projRecorderId));
		}
		
		// 保存项目参与人
		Map<String, List<String>> paramProjectAttendeeIds = 
			this.getAllRequestParameters(request, new String[] {"projectAttendeeId"});
		if (paramProjectAttendeeIds != null && paramProjectAttendeeIds.size() > 0)
		{
			List<String> empIds = paramProjectAttendeeIds.get("projectAttendeeId");
			entity.setProjectAttendeeIds(UtilString.join(empIds, ","));
			empIds = null;
		}
		
		// 保存项目合作方参与人
		Map<String, List<String>> paramProjectPartnerAttendeeIds = 
			this.getAllRequestParameters(request, new String[] {"partnerAttendeesId"});
		if (paramProjectPartnerAttendeeIds != null && paramProjectPartnerAttendeeIds.size() > 0)
		{
			List<String> empIds = paramProjectPartnerAttendeeIds.get("partnerAttendeesId");
			entity.setProjectPartnerAttendeeIds(UtilString.join(empIds, ","));
			empIds = null;
		}
	}
	
	/**
	 * 生成项目编号
	 * 
	 * 规则: {年月}{行业编号}{序列号}, e.g. 130801001
	 * 
	 * @param entity
	 * @return
	 */
	private String generateProjectNo (ModelProject entity) throws ServiceException
	{
		if (entity != null && entity.getProjectType() != null 
				&& !UtilString.isNotEmpty(entity.getProjectNo()))
		{
			StringBuilder builder = new StringBuilder();
			
			String year =  "";
			String month = "";
			
			if (entity.getProjectCreationTime() != null)
			{
				year = UtilDate.parseTime(entity.getProjectCreationTime(), "yy");
				month = UtilDate.parseTime(entity.getProjectCreationTime(), "MM");
			}
			else
			{
				year = UtilDate.parseTime(new Date(), "yy");
				month = UtilDate.parseTime(new Date(), "MM");
			}
			
			// 年
			builder.append(year);
			
			// 月
			builder.append(month);
			
			// 行业号
			builder.append(entity.getProjectType().getDictValue());
			
			// 获取序列号
			List<Object> maximumNo = this.serviceProject.findListByNativeSQL(
					"select max(SUBSTRING(p_no, 7, 3)) from app_project where p_no like '" + year + "%'");
			
			if (UtilCollection.isNotEmpty(maximumNo))
			{
				if (maximumNo.get(0) != null)
				{
					int seq = Integer.valueOf(maximumNo.get(0).toString()) + 1;
					builder.append(seq < 10 ? ("00" + seq) : ( seq < 100 ? ("0" + seq) : seq));
				}
				else
				{
					builder.append("001");
				}
			}
			else
			{
				builder.append("001");
			}
			
			return builder.toString();
		}
		
		return null;
	}
	
	/**
	 * 生成项目流程审批
	 * 
	 * @param project
	 */
	protected void generateProjectWorkFlow (ModelProject project) throws ServiceException
	{
		if (project != null)
		{
			// 获取当前激活的流程模板
			ModelFlowDef workflow = 
				this.serviceWorkFlow.getServiceFlowDefinition().getCurrentAppliedDefinition();
			
			Set<ModelProjectProcess> processForms = 
				this.convertFromFlowProcess(project, workflow);
			project.setProcessForms(processForms);
		}
	}
	
	/**
	 * 生成项目审批材料
	 * 
	 * @param project
	 */
	protected void generateProjectMaterials (ModelProject project) throws ServiceException
	{
		if (project != null)
		{
			// 获取当前材料设置模板
			List<ModelFlowMaterial> template = this.loadRootFlowMaterial(null);
			
			Set<ModelProjectMaterial> materials = 
				this.convertFromSetFlowMaterial(project, template);
			project.setMaterials(materials);
		}
	}
	
	/**
	 * 转换流程模板为项目审批流程表单
	 * 
	 * @param project
	 * @param process
	 */
	private Set<ModelProjectProcess> convertFromFlowProcess (ModelProject project, 
			ModelFlowDef workflow) throws ServiceException
	{
		if (project != null && workflow != null 
				&& UtilCollection.isNotEmpty(workflow.getTemplates()))
		{
			Set<ModelProjectProcess> projectWorkFlow = new HashSet<ModelProjectProcess>();
			
			for (ModelFlowTemplate node : workflow.getTemplates())
			{
				ModelProjectProcess process = new ModelProjectProcess();
				process.setProject(project);
				process.setConferenceFlag(node.getConferenceFlag());
				process.setMandatoryFlag(node.getMandatoryFlag());
				process.setNodeDesc(node.getNodeDesc());
				process.setNodeTitle(node.getNodeTitle());
				process.setNodeKey(node.getNodeKey());
				process.setSequence(node.getSequence());
				process.setToAuditRole(node.getToAuditRole());
				process.setDependedFlow(node.getDependedFlow());
				
				projectWorkFlow.add(process);
			}
			
			return projectWorkFlow;
		}
		else
		{
			throw new ServiceException("转换项目审批流程失败.");
		}
	}
	
	/**
	 * 转换流程材料为项目材料区
	 * 
	 * @param materials
	 * @return
	 */
	private Set<ModelProjectMaterial> convertFromSetFlowMaterial (ModelProject project, 
			List<ModelFlowMaterial> rootMaterials)
	{
		if (UtilCollection.isNotEmpty(rootMaterials))
		{
			Set<ModelProjectMaterial> setMaterials = new HashSet<ModelProjectMaterial>();
			
			for (ModelFlowMaterial rootMaterial : rootMaterials)
			{
				// 父材料节点
				ModelProjectMaterial rootPrjMaterial = 
					this.convertFromSingleFlowMaterial(project, rootMaterial);
				
				rootPrjMaterial.setMaterialParent(null);
				
				if (UtilCollection.isNotEmpty(rootMaterial.getMaterialChildren()))
				{
					// 子材料节点
					for (ModelFlowMaterial childMaterial : rootMaterial.getMaterialChildren())
					{
						ModelProjectMaterial childPrjMaterial = 
							this.convertFromSingleFlowMaterial(project, childMaterial);
						
						childPrjMaterial.setMaterialChildren(null);
						childPrjMaterial.setMaterialParent(rootPrjMaterial);
						
						rootPrjMaterial.addSubMaterial(childPrjMaterial);
					}
				}
				
				setMaterials.add(rootPrjMaterial);
			}
			
			return setMaterials;
		}
		
		return null;
	}
	
	/**
	 * 转换单个流程材料为项目材料
	 * 
	 * @param project
	 * @param material
	 * @return
	 */
	private ModelProjectMaterial convertFromSingleFlowMaterial (ModelProject project, 
			ModelFlowMaterial material)
	{
		if (material != null)
		{
			ModelProjectMaterial entity = new ModelProjectMaterial();
			
			entity.setMaterialDesc(material.getMaterialDesc());
			entity.setMaterialName(material.getMaterialName());
			entity.setMaterialType(material.getMaterialType());
			entity.setSequence(material.getSequence());
			entity.setProjectNo(project.getProjectNo());
			
			return entity;
		}
		
		return null;
	}
	
	public static Logger getLogger()
	{
		return LOGGER;
	}

	public void setServiceProject(ServiceProject serviceProject)
	{
		this.serviceProject = serviceProject;
	}

	public ServiceProject getServiceProject()
	{
		return serviceProject;
	}
	
	public static void main (String[] args)
	{
		System.out.println(UtilDate.parseTime(new Date(), "yyMM"));
	}

}
